import { getCookie, getQueryString } from '@inbiz/utils';
import { IUploaderProps } from '../interface';
import { checkAndCreateDocInfo, IsExistsHeadMd5 } from '../services';
import InBizUploaderTraditional from '../uploader-wrappers/traditional';
import { childFolderValidate, fileValidate, updateFileValidate, splitFileName, getFileMd5 } from './tool';

const initUploadData = (
  {
    fileModel = 'UPLOAD',
    repeatStrategy,
    showStrategyModal = false,
    createChildrenFolder,
    chunkSize = 5242880,
    itemLimit = 0,
    minSizeLimit = 0,
    sizeLimit = 0,
    allowedExtensions = [],
    ...props
  }: IUploaderProps,
  appInfo: any,
  ref: any,
  speedLimit: { DownloadLimit: number, UploadLimit: number },
  secondPass: boolean
) => {
  const { fileId, fileName, fileMode, accept, fileSize, folderId, events } = props;
  const fileChunkSize = speedLimit.UploadLimit || chunkSize;
  // 文件校验通过
  const fileVerificationPass = async (
    resData: any,
    data: any,
    file: any,
    meta: any,
    id: string | number,
  ) => {
    let fileMd5 = null;
    if (secondPass && file.size > 1024 * 1024) {
      const headMd5 = await getFileMd5(file, fileChunkSize, 'headMd5');
      const res = await IsExistsHeadMd5({ headMd5, regionId: resData.RegionId }) ?? { exists: false }
      if (res.exists) {
        fileMd5 = await getFileMd5(file, fileChunkSize);
      }
    }
    uploaderData.methods.setEndpoint(
      `${resData.RegionUrl ? resData.RegionUrl : ''}/document/upload?code=${getQueryString('code')}`,
    );
    uploaderData.methods.setParams(
      {
        regionId: resData.RegionId,
        chunkSize: fileChunkSize,
        regionHash: resData.RegionHash,
        fileName: data.fileName,
        type: data.type,
        undoOfError: false,
        fileMd5: fileMd5
      },
      id,
    );
    file.fileid = resData.FileId;
    file.fileverid = resData.FileVerId;
    file.parentfolderid = resData.ParentFolderId;
    file.ext = data.ext;
    file.meta = Object.keys(meta).length ? { ...meta } : {};
    file.regionUrl = resData.RegionUrl;
    file.fileMd5 = fileMd5;
  };

  const uploaderData = new InBizUploaderTraditional({
    options: {
      debug: false,
      chunking: {
        enabled: true,
        partSize: fileChunkSize,
        paramNames: {
          chunkSize: 'blockSize',
          totalParts: 'chunks',
          partIndex: 'chunk',
        },
      },
      maxConnections: 1,
      deleteFile: {
        enabled: true,
        endpoint: '/WebCore',
        method: 'post',
        forceConfirm: true,
      },
      autoUpload: true,
      request: {
        endpoint: '/document/upload',
        filenameParam: 'name',
        inputName: 'file',
        uuidName: 'uploadId',
        totalFileSizeName: 'size',
      },
      validation: {
        allowedExtensions: allowedExtensions,
        allowEmpty: true,
        itemLimit: itemLimit,
        minSizeLimit: minSizeLimit,
        sizeLimit: sizeLimit,
      },
      messages: {
        typeError: '{file} has an invalid extension. Valid extension(s): {extensions}.',
        sizeError: '{file} is too large, maximum file size is {sizeLimit}.',
        minSizeError: '{file} is too small, minimum file size is {minSizeLimit}.',
        emptyError: '{file} is empty, please select files again without it.',
        noFilesError: 'No files to upload.',
        tooManyItemsError:
          'Too many items ({netItems}) would be uploaded.  Item limit is {itemLimit}.',
        maxHeightImageError: 'Image is too tall.',
        maxWidthImageError: 'Image is too wide.',
        minHeightImageError: 'Image is not tall enough.',
        minWidthImageError: 'Image is not wide enough.',
        retryFailTooManyItems: 'Retry failed - you have reached your file limit.',
        onLeave: 'The files are being uploaded, if you leave now the upload will be canceled.',
        unsupportedBrowserIos8Safari:
          'Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari.  Please use iOS8 Chrome until Apple fixes these issues.',
      },
      callbacks: {
        onError: (
          id: string | number,
          name: string,
          errorReason: { code: string; tip: string },
        ) => {
          if (id == null || id == undefined) {
            return;
          }
          ref?.current.updateItemError(id, errorReason);
        },
        onUploadChunk: () => {
          if (speedLimit.UploadLimit > 0) {
            return Promise.resolve({
              isLimit: true
            })
          } else {
            return Promise.resolve();
          }
        },
        onUploadChunkSuccess: (id: number, chunkData: object, responseJSON: { status: string }) => {
          const file = uploaderData.methods.getFile(id);
          const { status } = responseJSON
          if (status === 'End' && file.fileMd5) {
            uploaderData.methods.cancel(id, true)
          }
        },
        onUpload: function (id: number, name: string) {
          let file = uploaderData.methods.getFile(id);
          const { name: newName, ext } = splitFileName(name);
          const {
            fileId: paramFileId,
            fileName: paramFileName,
            folderId: paramFolderId,
            meta = {},
            ...otherParams
          } = uploaderData.methods._paramsStore.get(id) || {};
          const { webkitRelativePath } = file;
          // 文件上传验证类型和大小
          const isFileThrough = fileValidate({ file, accept, fileMode, fileSize });
          if (!isFileThrough) {
            uploaderData.methods.cancel(id);
            return;
          }
          // 子文件夹创建时验证
          let fullPath = childFolderValidate(createChildrenFolder) ?? '';
          if (createChildrenFolder && !fullPath && fullPath != '') {
            uploaderData.methods.cancel(id);
            return;
          }
          // 更新文件时验证
          if (paramFileId || fileId) {
            const isUpdateFileThrough = updateFileValidate(paramFileName || fileName, file);
            if (!isUpdateFileThrough) return;
          }
          file.folderId = paramFolderId ? paramFolderId : file?.folderId;
          file.isChunk = file.size > fileChunkSize;
          let exitStatus = uploaderData.qq.status.UPLOAD_EXISNAME;
          let pausedStatus = uploaderData.qq.status.PAUSED;
          // 初始化参数
          const initParams = () => {
            if (webkitRelativePath) {
              fullPath += `/${webkitRelativePath.substring(
                0,
                webkitRelativePath.lastIndexOf('/'),
              )}`;
            }
            let data: any = {
              masterFileId: otherParams?.masterFileId || otherParams?.masterFileld, // 兼容老版错误写法，项目上有用到masterFileld
              token: getCookie('token'),
              fileName: name,
              fileRemark: '',
              size: file.size,
              type: file.type,
              attachType: 0,
              fullPath: fullPath, // 配置子文件夹生成路径
              code: getQueryString('code'),
              strategy: repeatStrategy || 'majorUpgrade',
              lastModifiedDate: new Date(),
              fileModel: 'UPLOAD',
              ext: ext,
            };
            if (data.fileModel == 'UPLOAD') {
              data.folderId = paramFolderId ? paramFolderId : folderId;
            } else if (data.fileModel == 'UPDATE') {
              data.fileId = paramFileId ? paramFileId : fileId;
              data.folderId = paramFolderId ? paramFolderId : folderId;
            }
            if (file.qqPath) {
              data.fullPath = '/' + file.qqPath;
            }
            if (paramFileId || fileId) {
              data.fileId = paramFileId ? paramFileId : fileId;
              data.fileModel = 'UPDATE';
            }
            file.model = data.fileModel;
            if (file.status == exitStatus) {
              data.strategy = file.strategy;
              data.fileModel = file.fileModel;
              data.fileName = file.filename || file.fileName;
            }
            return {
              ...data,
              ...otherParams
            };
          };
          const promise = new Promise(async function (resolve, reject) {
            if (
              (!file.status || file.status === pausedStatus || file.status === exitStatus) &&
              file.fileid
            ) {
              resolve({ success: true });
            } else {
              // 异步处理
              if (file?.strategy === 'skip' && file.fileModel == 'UPDATE') {
                reject({
                  responseJSON: { error: '已跳过' },
                });
                return;
              }
              if (file.size == 0) {
                reject({
                  responseJSON: { error: '文件内容为空，如需上传请重试' },
                });
                return;
              }
              let data = initParams();
              const res = (await events?.current?.onBeforeUpload?.(data)) ?? data;
              if (!res) {
                reject({});
                return;
              }
              data = res;
              file.folderId = data.folderId;
              checkAndCreateDocInfo(data).then(async (res) => {
                const resData = res.data;
                if (res.result == 0) {
                  await fileVerificationPass(resData, data, file, meta, id);
                  resolve({ success: res.result });
                } else if (res.result == 610) {
                  file.isRename = true;
                  file.errorInfo = res?.errorInfo;
                  if (!showStrategyModal) {
                    data.fileModel = repeatStrategy === 'rename' ? 'UPLOAD' : 'UPDATE';
                    data.fileName =
                      repeatStrategy === 'rename'
                        ? `${newName}${Date.now()}.${ext}`
                        : data.fileName;
                    file.filename = data.fileName;
                    file.ext = data.ext;
                    file.strategy = data.strategy;
                    checkAndCreateDocInfo(data).then(async (res) => {
                      let resData = res.data;
                      if (res.result == 0) {
                        await fileVerificationPass(resData, data, file, meta, id);
                        if (data.strategy === 'skip' && data.fileModel == 'UPDATE') {
                          reject({
                            responseJSON: { error: { code: res.result, tip: res.reason } },
                          });
                        }
                        const result: any = { success: res.result };
                        resolve(result);
                      }
                    });
                  } else {
                    resolve({ success: res.result, pause: true, exist: true });
                  }
                } else {
                  // 多语言转换
                  if (res.result == 611) {
                    reject({
                      responseJSON: { error: { code: res.result, tip: 'inbizUpload.banFileType' } },
                    });
                  } else if (res.result == 816) {
                    reject({
                      responseJSON: {
                        error: { code: res.result, tip: 'inbizUpload.parentNoPermission' },
                      },
                    });
                  } else {
                    reject({ responseJSON: { error: { code: res.result, tip: res.reason } } });
                  }
                }
              });
              // 处理结束后、调用resolve 或 reject
            }
          });
          return promise;
        },
        onAllComplete: function (successIds: number[], failedIds: number[]) {
          const statusEnum = uploaderData.qq.status;
          const fileList = ref?.current.getfileList();
          // 修复上传完成事件偶发多次触发
          const isUploadingFile = fileList.some(item => item?.status !== statusEnum.UPLOAD_SUCCESSFUL && item?.status !== statusEnum.UPLOAD_FAILED);
          if (isUploadingFile) {
            return;
          }
          if (successIds.length === 0 && failedIds.length === 0) {
            return;
          }
          const successList = successIds.map((item) => {
            const file = uploaderData.methods.getFile(item);
            return { ...file };
          });
          const failedList = failedIds.map((item) => {
            const file = uploaderData.methods.getFile(item);
            return { ...file };
          });
          ref?.current.onComplete({ successList, failedList, fileList });
        }
      },
    },
  });
  return uploaderData;
};

export default initUploadData;
